package com.cloud.sky.component;


import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Map;
import java.util.HashMap;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpMethod;

import java.util.*;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpUtil {

    private static String endpoint = "https://cloud-api.tingyutech.com";
    private static String accessKey = "K7Re_pDnwM912G0t7mcpscvd";
    private static String accessSecret = "Qk6cCWPQ6tz9cV8SFMWXS8U4eg1hIkCu";
    private static String signatureVersion = "2.0";
    private static String contentType = "application/json";
    private static ObjectMapper objectMapper = new ObjectMapper();
    public static String GET = "GET";
    public static String POST = "POST";
    public static String PUT = "PUT";
    public static String DELETE = "DELETE";

    public static void main(String[] args) throws Exception {

        Map<String, Object> body = new HashMap<>();
        Map<String, Object> query = new HashMap<>();

        String pathname = "/jusha/v2/machine/all/list";
        String method = "GET";
        call(pathname, method, query, body);
    }

    public static String generateRequestUrl(String path, Map<String, Object> query) throws Exception {
        String reqUrl = endpoint + path;
        if (!query.isEmpty()) {
            String orderedQueryString = keyPairsToOrderedString(query);
            reqUrl = reqUrl + "?" + orderedQueryString;
        }
        return reqUrl;
    }

    /**
     * 发送请求
     */
    public static String call(String path, String method, Map<String, Object> query, Map<String, Object> body) throws Exception {

        Map<String, Object> queryParam = query == null ? new HashMap<>() : query;

        Map<String, Object> bodyParam = body == null ? new HashMap<>() : body;


        Long requestTime = System.currentTimeMillis();
        String reqUrl = generateRequestUrl(path, queryParam);

        Map<String, String> headers = new HashMap<>();
        headers.put("x-ty-timestamp", requestTime + "");
        headers.put("x-ty-accesskey", accessKey);
        headers.put("x-ty-signature-version", signatureVersion);
        headers.put("content-type", contentType);

        Map<String, Object> customHeaders = new HashMap<>();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue() == null ? "" : entry.getValue();
            if (key.startsWith("x-ty-")) {
                customHeaders.put(key, value);
            }
        }

        String orderedCustomHeaderString = keyPairsToOrderedString(customHeaders);
        String orderedQueryString = keyPairsToOrderedString(queryParam);


        String bodyJsonString = objectMapper.writeValueAsString(bodyParam);
        String body_hash = bodyParam.isEmpty() ? "" : getHashSHA256HexStr(bodyJsonString);

        String[] array = {
                fixedEncodeURIComponent(path),
                fixedEncodeURIComponent(method),
                fixedEncodeURIComponent(contentType),
                orderedCustomHeaderString,
                orderedQueryString,
                body_hash,
                requestTime + "",
                accessKey,
                signatureVersion,
        };
        StringBuilder sb = new StringBuilder();

        for (String s : array) {
            sb.append(s).append("\n");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1); // 删除最后一个 & 符号
        }
        String result = sb.toString();

        String targetSignature = getHmacSHA256HexStr(result, accessSecret);


        URL url = new URL(reqUrl);
        HttpURLConnection con = (HttpURLConnection) url.openConnection();
        con.setRequestMethod(method);
        con.setDoOutput(true);
        // 将header设置到连接对象中
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            con.setRequestProperty(entry.getKey(), entry.getValue());
        }
        con.setRequestProperty("Authorization", targetSignature);

        if (!bodyParam.isEmpty()) {
            try (OutputStream os = con.getOutputStream()) {
                byte[] input = bodyJsonString.getBytes(StandardCharsets.UTF_8);
                os.write(input, 0, input.length);
            }
        }

        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
            StringBuilder response = new StringBuilder();
            String responseLine;
            while ((responseLine = br.readLine()) != null) {
                response.append(responseLine.trim());
            }
            return response.toString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 数据进行排序拼接
     */
    public static String keyPairsToOrderedString(Map<String, Object> keyPairs) throws Exception {
        List<String> keys = new ArrayList<>(keyPairs.keySet());
        Collections.sort(keys);

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            Object value = keyPairs.get(key) == null ? "" : keyPairs.get(key);
            sb.append(fixedEncodeURIComponent(key));
            sb.append("=");
            sb.append(fixedEncodeURIComponent(String.valueOf(value)));
            sb.append("&");
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1); // 删除最后一个 & 符号
        }
        String result = sb.toString();
        return result;
    }

    /**
     * 数据进行encode
     */
    public static String fixedEncodeURIComponent(String str) throws Exception {
        Pattern pattern = Pattern.compile("[!'()*]");
        Matcher matcher = pattern.matcher(str);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            String c = matcher.group();
            matcher.appendReplacement(buffer, "%" + Integer.toHexString(c.charAt(0)).toUpperCase());
        }
        matcher.appendTail(buffer);
        str = buffer.toString();
        str = URLEncoder.encode(str, StandardCharsets.UTF_8.toString()).replaceAll("\\+", "%20");
        return str;
    }

    /**
     * 将数据进行 SHA-256 HASH
     */
    public static String getHashSHA256HexStr(String data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(data.getBytes());
        String hex = bytesToHex(hash);
        return hex;
    }

    private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = HEX_ARRAY[v >>> 4];
            hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

    /**
     * HmacSHA256 数据加密
     */
    public static String getHmacSHA256HexStr(String data, String secret) throws Exception {
        SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        byte[] rawHmac = mac.doFinal(data.getBytes());

        StringBuilder hexString = new StringBuilder();
        for (byte b : rawHmac) {
            String hex = Integer.toHexString(0xFF & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

